import fun.parser.Tree;
import ic.ast.Node;
import ic.ast.decl.*;

import java.util.HashMap;

public class ProgramParser extends BaseParser {

	// @formatter:off
	private final static String GRAMMAR =
		  "               S -> program\n"
		+ "         program -> class_decl program | \n"
		+ "       class_decl -> class CLASS_ID opt_extends { members } \n"
		+ "     opt_extends -> extends CLASS_ID | \n"
		+ "         members -> member members | \n"
		+ "          member -> field | method \n"
		+ "           field -> type ids ; \n"
		+ "             ids -> ID | ID , ids \n"
		+ "          method -> opt_modifier weaktype ID ( opt_formals ) { opt_stmts } \n"
		+ "    opt_modifier -> static | \n"
		+ "        weaktype -> type | void \n"
		+ "     opt_formals -> formals | \n"
		+ "         formals -> formal | formal , formals \n"
		+ "          formal -> type ID \n"
		+ "            type -> int | boolean | string | CLASS_ID | type [ ] \n"
		+ "       opt_stmts -> stmt opt_stmts | \n"
		+ "        opt_expr -> expr | \n"
		+ "    stmt_control -> stmt_location | stmt_call | stmt_return | stmt_ifelse | stmt_while | stmt_break | stmt_continue | stmt_block \n"
		+ "stmt_control_ext -> stmt_control | stmt_if \n"
		+ "            stmt -> stmt_control_ext | stmt_type \n"
		+ "   stmt_location -> location = expr ; \n"
		+ "       stmt_call -> call ; \n"
		+ "     stmt_return -> return opt_expr ; \n"
		+ "     stmt_ifelse -> if ( expr ) stmt_control else stmt_control_ext \n"
		+ "         stmt_if -> if ( expr ) stmt_control_ext \n"
		+ "      stmt_while -> while ( expr ) stmt_control_ext \n"
		+ "      stmt_break -> break ; \n"
		+ "   stmt_continue -> continue ; \n"
		+ "      stmt_block -> { opt_stmts } \n"
		+ "       stmt_type -> formal opt_equal ; \n"
		+ "       opt_equal -> = expr | \n"
		+ "            expr -> expr12 \n"
		+ "          expr12 -> expr12 || expr11 | expr11 \n"
		+ "          expr11 -> expr11 && expr10 | expr10 \n"
		+ "          expr10 -> expr10 == expr09 | expr10 != expr09 | expr09 \n"
		+ "          expr09 -> expr09 < expr08 | expr09 > expr08 | expr09 <= expr08 | expr09 >= expr08 | expr08 \n"
		+ "          expr08 -> expr08 + expr07 | expr08 - expr07 | expr07 \n"
		+ "          expr07 -> expr07 * expr06 | expr07 / expr06 | expr07 % expr06 | expr06 \n"
		+ "          expr06 -> - expr06 | expr05 \n"
		+ "          expr05 -> ! expr05 | expr04 \n"
		+ "          expr04 -> new type [ expr ] | expr03 \n"
		+ "          expr03 -> expr02 . length | expr02 \n"
		+ "          expr02 -> call | location | expr01 \n"
		+ "          expr01 -> this | new CLASS_ID ( ) | literal | ( expr ) \n"
		+ "            call -> static_call | virtual_call \n"
		+ "     static_call -> CLASS_ID . ID ( opt_exprs ) \n"
		+ "       opt_exprs -> exprs | \n"
		+ "           exprs -> expr , exprs | expr \n"
		+ "    virtual_call -> opt_this ID ( opt_exprs ) \n"
		+ "        opt_this -> expr04 . | \n" // TODO: change to expr02?
		+ "        location -> opt_this ID | expr03 [ expr ] \n"
		+ "         literal -> INTEGER | STRING | true | false | null \n";
	// @formatter:on

	public ProgramParser() {
		super(GRAMMAR);
	}

	@Override
	protected Node constructAst(Tree parseTree) {
		return (Program)(new RNodeS().recurse(parseTree, new HashMap<String, Functor>()));
	}
}
